package com.marvels.approve.process.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.marvels.approve.common.service.ISysUserService;
import com.marvels.approve.common.service.McamLoanApplyInfoCommonService;
import com.marvels.approve.consum.ApproveConsumerFinancialApi;
import com.marvels.approve.consum.ApproveConsumerSystemApi;
import com.marvels.approve.loan.dao.IMcamLoanApplyInfoDao;
import com.marvels.approve.loan.dto.LoanAfterInfoDTO;
import com.marvels.approve.loan.dto.McamAcLoanApplyImageInfo;
import com.marvels.approve.loan.dto.McamLoanApplyInfoDTO;
import com.marvels.approve.loan.dto.McsmSystemParam;
import com.marvels.approve.manager.dao.ICaseManagerDao;
import com.marvels.approve.manager.dao.ICaseManagerProductTypeDao;
import com.marvels.approve.manager.dao.IOpinionDao;
import com.marvels.approve.manager.dto.CaseManagerDTO;
import com.marvels.approve.manager.dto.CaseManagerProductTypeDTO;
import com.marvels.approve.manager.dto.OpinionDTO;
import com.marvels.approve.manager.service.IActivityLoadingService;
import com.marvels.approve.mqueues.service.ApproveILoanApplyQueueService;
import com.marvels.approve.process.consum.ConsumerExternalFacesigApi;
import com.marvels.approve.process.dao.AttachmentInfoDao;
import com.marvels.approve.process.dao.ILoanApplyCaseDao;
import com.marvels.approve.process.dao.ILoanApplyCaseLogDao;
import com.marvels.approve.process.dao.McamResignStateMsgDao;
import com.marvels.approve.process.dto.ApiResponse;
import com.marvels.approve.process.dto.CompleteProcessDTO;
import com.marvels.approve.process.dto.HandleProcessDTO;
import com.marvels.approve.process.dto.KimGeXinQianInfo;
import com.marvels.approve.process.dto.KimGeXinQianInfo.SignInfo;
import com.marvels.approve.process.dto.LaAttachmentDTO;
import com.marvels.approve.process.dto.LoanApplyCaseDTO;
import com.marvels.approve.process.dto.LoanApplyCaseLogDTO;
import com.marvels.approve.process.dto.McamResignStateMsgDTO;
import com.marvels.approve.process.dto.ProtocolTemplateInfoDTO;
import com.marvels.approve.process.dto.QueryStatusNumDTO;
import com.marvels.approve.process.dto.ResignExternalDTO;
import com.marvels.approve.process.dto.SysUserDTO;
import com.marvels.approve.process.dto.SysUserRoleDTO;
import com.marvels.approve.process.service.AttachmentInfoService;
import com.marvels.approve.process.service.ILoanApplyCaseLogService;
import com.marvels.approve.process.service.ILoanApplyCaseService;
import com.marvels.approve.process.service.IProcessService;
import com.marvels.approve.process.service.ProtocolTemplateInfoService;
import com.marvels.common.constants.CaseNodeConstant;
import com.marvels.common.constants.LoanStateConstant;
import com.marvels.common.dto.UserDTO;
import com.marvels.common.exception.MarvelsBusinessException;
import com.marvels.common.utils.CacheUtils;
import com.marvels.common.utils.DateUtils;
import com.marvels.common.utils.MarvelsLogUtil;
import com.marvels.common.utils.ServerProperties;
import com.marvels.common.utils.ThreadContextUtil;

import freemarker.template.Configuration;
import freemarker.template.Template;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
@Service
public class ProcessServiceImpl implements IProcessService {
	@Autowired
	private ILoanApplyCaseService loanApplyCaseService;
	@Autowired
	private IMcamLoanApplyInfoDao mcamLoanApplyInfoDao;
	@Autowired
	private ICaseManagerProductTypeDao caseManagerProductTypeDao;
	@Autowired
	private IActivityLoadingService activityLoadingService;
	@Autowired
	private ICaseManagerDao caseManagerDao;
	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private ILoanApplyCaseLogDao loanApplyCaseLogDao;
	@Autowired
	private ILoanApplyCaseLogService loanApplyCaseLogService;
	@Autowired
	private McamLoanApplyInfoCommonService mcamLoanApplyInfoCommonService ;
	@Autowired
	private ApproveILoanApplyQueueService loanApplyQueueService;
	@Autowired
	private ILoanApplyCaseDao iLoanApplyCaseDao;
	@Autowired
	private IOpinionDao iOpinionDao;
	@Autowired
	private AttachmentInfoService attachmentInfoService;
	@Autowired
	private ProtocolTemplateInfoService protocolTemplateInfoService;
	@Autowired
	private ApproveConsumerSystemApi consumerSystemApi;
	@Value("${config.properties.path}")
	private  String configPropertiesPath;
	@Autowired
	private ApproveConsumerFinancialApi consumerFinancialApi;
	@Autowired
	private AttachmentInfoDao attachmentInfoDao;
	@Autowired
	private ConsumerExternalFacesigApi consumerExternalFacesigApi;
	private static final double MAX_VALUE = 9999999999999.99D;
	private static final String UNIT = "万仟佰拾亿仟佰拾万仟佰拾元角分";
	private static final String DIGIT = "零壹贰叁肆伍陆柒捌玖";
	@Autowired
	private McamResignStateMsgDao mcamResignStateMsgDao;
	@Override
	public QueryStatusNumDTO queryStatusNum(HandleProcessDTO handleProcessDTO) throws MarvelsBusinessException {
		// TODO 自动生成的方法存根
		QueryStatusNumDTO dto = new QueryStatusNumDTO();
		Integer decision = 0;//待决策
		Integer waiting = 0;//待处理
		/*Integer processing = 0;//处理中
		Integer patch = 0;//退回补件*/
		Integer processed = 0;//已处理
		Integer decisionRefuseing = 0;// 决策拒绝
		UserDTO user = CacheUtils.getCacheUser();
		Integer userId = user.getUserId();
		String userCode = user.getUserCode();
		decision = findDecision();
		// 获取决策拒绝数量
		McamLoanApplyInfoDTO param = new McamLoanApplyInfoDTO();
		param.setStatus(LoanStateConstant.SR4);
		decisionRefuseing = mcamLoanApplyInfoDao.selectCount(param);
		
		waiting = findWaitProcess(userId,handleProcessDTO.getQueryNodes());
		//已处理
		processed = findStatusNumProcessed(userCode);
		//处理中  退回补件
		Map<String,Integer> numMap = findStatusNumNotProcessed(userCode);
		dto.setDecision(decision);
		dto.setWaiting(waiting);
		dto.setProcessed(processed);
		dto.setProcessing(numMap.get("processing"));
		dto.setPatch(numMap.get("patch"));
		dto.setDecisionRefuseing(decisionRefuseing);
		return dto;
	}
	/**跑决策 J00状态的单为未跑决策的单
	 * @author 何杰
	 * 2018年4月19日
	 * @return
	 * @throws MarvelsBusinessException 
	 */
	private Integer findDecision() throws MarvelsBusinessException{ 
		return loanApplyQueueService.findLoanApplyQueueCount();
	}
	/**获取待取件件数
	 * @author 何杰
	 * 2018年4月16日
	 * @param userId
	 * @return
	 */
	private Integer findWaitProcess(Integer userId,List<String> queryNodes) throws MarvelsBusinessException{
		SysUserDTO dto = this.sysUserService.querySysUser(userId);
		MarvelsLogUtil.getInstance().info(userId+"-----------------userId:"+dto);
		List<SysUserRoleDTO> roles = dto.getRoles();
		List<String> roleCodes = new ArrayList();
		int count = roles.size();
		for(int i=0;i<count;i++){
			roleCodes.add(roles.get(i).getRoleCode());
		}
		HandleProcessDTO handleProcessDTO = new HandleProcessDTO();
		handleProcessDTO.setQueryNodes(queryNodes);
		handleProcessDTO.setRoleCodes(roleCodes);
		List<String> nodes = loanApplyCaseService.findUserNodes(handleProcessDTO);
		return loanApplyCaseService.findWaitProcessNum(roleCodes,nodes);
	}
	//处理中  退回补件
	private Map<String,Integer> findStatusNumNotProcessed(String userCode)throws MarvelsBusinessException{
		Map<String,Integer> result = new HashMap();
		Integer processing = 0;//处理中
		Integer patch = 0;//退回补件
		LoanApplyCaseDTO processedDTO = new LoanApplyCaseDTO();
		processedDTO.setAssignee(userCode);  
		processedDTO.setPageSize(100);
		List<LoanApplyCaseDTO> cases = this.loanApplyCaseService.findLoanApplyCases(processedDTO);
		int size = cases.size();
		for(int i=0;i<size;i++){
			LoanApplyCaseDTO entity = cases.get(i);
//			ZX0；审批退回：‘SP9’；补件重提：BJ8；审批新近件：SP0；审计退回：‘SJ8’；征信重提：ZX8；审计新进件：SJ0；审批重提：SP8；征信退回‘ZX9’;材料审核退回‘CL9’;征信报告核对退回‘ZP9’;征信报告录入退回：‘ZI9’
			String caseStatus = entity.getCaseStatus();
			if(caseStatus!=null && (caseStatus.equals("SP9") || caseStatus.equals("SJ8") || caseStatus.equals("ZX9")|| caseStatus.equals("CL9")|| caseStatus.equals("ZP9") || caseStatus.equals("ZI9"))){
				patch++;
			}else{
				processing++;
			}
		}
		result.put("processing", processing);
		result.put("patch",patch);
		return result;
	}
	//已处理
	private Integer findStatusNumProcessed(String userCode){
//		Calendar cal = Calendar.getInstance();
//		cal.set(Calendar.HOUR_OF_DAY, 0);
//		cal.set(Calendar.MINUTE,0);
//		cal.set(Calendar.SECOND,0);
//		Date startCreatedDate = cal.getTime();
//		MarvelsLogUtil.getInstance().info("查询日期："+startCreatedDate);
		//处理日志表查询
		LoanApplyCaseLogDTO loanApplyCaseLog = new LoanApplyCaseLogDTO();
		loanApplyCaseLog.setAssignee(userCode);
		Integer count = loanApplyCaseLogDao.findStatusNumProcessed(loanApplyCaseLog);
		return count;
	}
	
	@Transactional(timeout = 30 ,rollbackFor=Exception.class)
	public LoanApplyCaseDTO handleProcess(HandleProcessDTO handleProcessDTO) throws MarvelsBusinessException {
		//统一取件
//		//取贷款信息
//		McamLoanApplyInfoDTO info = getLoanApplyInfo("Z00","Z01");
//		//获取产品流程
//		CaseManagerProductTypeDTO cmptDTO = getCaseManagerProductType(info);
//		//获取流程
//		loadProcess(cmptDTO);
		//1\拿用户角色
		UserDTO user = CacheUtils.getCacheUser();
		if(user == null){
			throw new MarvelsBusinessException("无法获取登录信息,token:"+ThreadContextUtil.get("l-token"));
		}
		SysUserDTO dto = this.sysUserService.querySysUser(user.getUserId());
		if(dto==null){
			throw new MarvelsBusinessException("无法获取到操作人信息,操作人ID:"+user.getUserId());
		}
		List<SysUserRoleDTO> roles = dto.getRoles();
		List<String> roleCodes = new ArrayList();
		int count = roles==null?0:roles.size();
		for(int i=0;i<count;i++){
			roleCodes.add(roles.get(i).getRoleCode());
		}
		handleProcessDTO.setRoleCodes(roleCodes);
	    //2\可以处理那些节点的单   
		List<LoanApplyCaseDTO> loanApplyCases = loanApplyCaseService.findLoanApplyCases(handleProcessDTO);
	    //3\获取这些节点下那些贷款单 
	    //4\拿去1单处理  
	    //5\修改mcam_loan_apply_case update assignee is null
		if(loanApplyCases==null||loanApplyCases.size()<1){
			throw new MarvelsBusinessException("无可取单"+user.getUserCode());
		}
		int size = loanApplyCases.size();
		for(int i=0;i<size;i++){
			LoanApplyCaseDTO loanApplyCase = loanApplyCases.get(i);
			loanApplyCase.setCurAssignee(null);
			loanApplyCase.setAssignee(user.getUserCode());
			loanApplyCase.setAssigneeName(user.getUserName());
			//loanApplyCase.setUpdatedBy(user.getUserCode());
			Integer caseVersion = loanApplyCase.getCaseVersion();
			loanApplyCase.setCaseVersion(caseVersion==null?1:caseVersion);
			LoanApplyCaseDTO loanApplyCaseDto = this.loanApplyCaseService.pickupLoanApplyCases(loanApplyCase);
			if(loanApplyCaseDto != null){
				//写入log
				loanApplyCaseLogService.commCompleteCase(loanApplyCaseDto,null);
				return loanApplyCaseDto;
			}
		}
		throw new MarvelsBusinessException("未抢到处理工单"+user.getUserCode());
	} 
	//征信，审批，审计 状态流转
	private void modifyStatus(String loanId)throws MarvelsBusinessException {
		McamLoanApplyInfoDTO loanInfo = mcamLoanApplyInfoDao.selectMcamLoanApplyInfoByLoanId(loanId);
		String status = loanInfo.getStatus();
		String nextStatus = "";
		if(LoanStateConstant.Z00.equals(status)) {
			nextStatus = LoanStateConstant.Z01;
		}else if(LoanStateConstant.S01.equals(status)) {
			nextStatus = LoanStateConstant.S00;
		}else if(LoanStateConstant.C01.equals(status)) {
			nextStatus = LoanStateConstant.C00;
		}
		mcamLoanApplyInfoCommonService.updateMcamLoanApplyInfoStatusByLoanId(loanId, nextStatus, status, null);
	}
	//无用代码
	private void loadProcess(CaseManagerProductTypeDTO cmptDTO)throws MarvelsBusinessException{
		//获取流程管理
		CaseManagerDTO caseManagerDTO = new CaseManagerDTO();
		caseManagerDTO.setActKey(cmptDTO.getActKey());
		caseManagerDTO.setStatus(0);
		List<CaseManagerDTO> managers = this.caseManagerDao.select(caseManagerDTO);
		if(managers == null || managers.size() != 1){
			throw new MarvelsBusinessException(cmptDTO.getActName()+"流程管理查询异常");
		}
		CaseManagerDTO manager = managers.get(0);
		//获取第一个节点
		String nodes =activityLoadingService.getFirstNodes(manager);
		//这里临时写一个
		String[] ns = nodes.split(",");
		String nodeCode = ns[0];
		boolean isOk = checkNodeRole(nodeCode,"userId");
		if(isOk){
			String proId = activityLoadingService.findProcess(cmptDTO.getActKey(), "systemhj");
		}else{
			throw new MarvelsBusinessException("userId"+"无权限获取");
		}
	}
	//无用代码
	public boolean checkNodeRole(String node, String userId){
		//获取用户权限
		//节点权限是否满足条件
		return false;
	}
	//取贷款信息第一条  无用代码
	private McamLoanApplyInfoDTO getLoanApplyInfo(String status,String nextStatus)throws MarvelsBusinessException{
		McamLoanApplyInfoDTO info = mcamLoanApplyInfoDao.selectFirstStatus(status);
		if(info==null){
			throw new MarvelsBusinessException("无可取件");
		}
		info.setOldStatus(info.getStatus());
		info.setStatus(nextStatus);
		int count = this.mcamLoanApplyInfoDao.updateByPrimaryKeySelective(info);
		if(count==1){
			return info;
		}else{
			throw new MarvelsBusinessException(info.getCustName()+"的件已经被取走");
		}
	}
	
	/**获取流程   无用代码
	 * @author 何杰
	 * 2018年4月14日
	 * @param info
	 */
	private CaseManagerProductTypeDTO getCaseManagerProductType(McamLoanApplyInfoDTO info)throws MarvelsBusinessException{
		//查询产品流程
		CaseManagerProductTypeDTO cmptDTO = new CaseManagerProductTypeDTO();
		String productType = info.getProductType();
		cmptDTO.setProductType(productType);
		cmptDTO.setStatus(0);
		List<CaseManagerProductTypeDTO> cmpts = caseManagerProductTypeDao.select(cmptDTO);
		if(cmpts!=null && cmpts.size()>0){
			cmptDTO = cmpts.get(0);
		}else{
			throw new MarvelsBusinessException(info.getProductName()+"产品无可走流程");
		}
		return cmptDTO;
	}
	@Override
	@Transactional(timeout = 30 ,rollbackFor=Exception.class)
	public LoanApplyCaseDTO completeLoanApplyCase(CompleteProcessDTO completeProcessDTO)
			throws MarvelsBusinessException {
		// 完成当前节点
		return this.loanApplyCaseService.completeNode(completeProcessDTO);
	}
	@Override
	public LoanApplyCaseDTO handleZSJProcess(HandleProcessDTO handleProcessDTO) throws MarvelsBusinessException {
		LoanApplyCaseDTO caseDto = handleProcess(handleProcessDTO);
		//征信，审批，审计 状态流转
		modifyStatus(caseDto.getLoanId());
		return caseDto;
	}
	
	
	
	/**查询退回app退回原因
	 * @author 娄凯琦
	 * @date 2018年9月27日  
	 * @param loanApplyCaseDTO
	 * @return
	 */
	@Override
	public List<OpinionDTO> queryRefusedReason(LoanApplyCaseDTO loanApplyCaseDTO) throws MarvelsBusinessException {
		if(loanApplyCaseDTO==null||loanApplyCaseDTO.getLoanId()==null){
			throw new MarvelsBusinessException("传入参数为空");
		}
		MarvelsLogUtil.getInstance().info("ProcessServiceImpl .queryRefusedReason loanId ===="+loanApplyCaseDTO.getLoanId());
		loanApplyCaseDTO = iLoanApplyCaseDao.selectByLoanId(loanApplyCaseDTO.getLoanId());
		OpinionDTO param = new OpinionDTO();
		param.setLoanId(loanApplyCaseDTO.getLoanId());
		param.setCaseVersion(loanApplyCaseDTO.getCaseVersion());
		param.setNodeCode(loanApplyCaseDTO.getCurNodeCode());
		param.setOpinionClass(4);
		return iOpinionDao.selectOpinion(param);
	}

	/**签合同
	 * @author 娄凯琦
	 * @date 2018年9月28日  
	 * @param loanId
	 * @throws MarvelsBusinessException
	 */
	@Override
	public boolean loanCompactSign(String loanId) throws MarvelsBusinessException {
		if(StringUtils.isEmpty(loanId)){
			throw new MarvelsBusinessException("传入loanId为空");
		}
		MarvelsLogUtil.getInstance().info("ProcessServiceImpl loanCompactSign loanId===="+loanId);
		LaAttachmentDTO laAttachmentDTO = new LaAttachmentDTO();
		laAttachmentDTO.setLoanId(loanId);
		laAttachmentDTO.setAtmtType("Q_MQ");//Q_MQ表示签名附件
		List<LaAttachmentDTO> attList = attachmentInfoService.getAttachmentByLoanIdAndType(laAttachmentDTO);//查询附件
		if(attList == null || attList.size()==0){
			throw new MarvelsBusinessException("查询附件为空loanId==="+loanId);
		}
		LaAttachmentDTO cmAttachment = attList.get(0);
		String imgFilePath = cmAttachment.getFileLocation();
		String picBase64 = readCustomerDignaturePic(imgFilePath);
		
		McamLoanApplyInfoDTO mcamLoanApplyInfoDTO = mcamLoanApplyInfoDao.selectMcamLoanApplyInfoByLoanId(loanId);//查询贷款申请信息
		MarvelsLogUtil.getInstance().info("ProcessServiceImpl loanCompactSign mcamLoanApplyInfoDTO===="+mcamLoanApplyInfoDTO);
		List<ProtocolTemplateInfoDTO> templateList = protocolTemplateInfoService.queryTemplateInfoDTOByLoanId(loanId);
		
		if(templateList==null||templateList.size()==0){
			throw new MarvelsBusinessException("查询的模板为空loanId==="+loanId);
		}
		
		boolean flag = false;
		for (ProtocolTemplateInfoDTO protocolTemplateInfo : templateList) {
			if("bs_authorize_template.ftl".equals(protocolTemplateInfo.getTemplateFileName())||"bs_bank_protocol_template.ftl".equals(protocolTemplateInfo.getTemplateFileName())
					||"bs_loan_contract_template.ftl".equals(protocolTemplateInfo.getTemplateFileName())||"bs_person_certificate_apply.ftl".equals(protocolTemplateInfo.getTemplateFileName())
					||"bs_digital_certificate_trust.ftl".equals(protocolTemplateInfo.getTemplateFileName())){//宝生特有的合同，我们这边不在调签章
				continue;
			}
			MarvelsLogUtil.getInstance().info("ProcessServiceImpl loanCompactSign protocolTemplateInfo===="+protocolTemplateInfo);
			//签署协议
			flag = electronSignAndSeal(loanId,picBase64,protocolTemplateInfo,mcamLoanApplyInfoDTO);
		}
		return flag;
		//发送邮件
//		if(flag){
//			sendErrorMailMsg("SUCCESS",dataMap.get("userId")+"",dataMap.get("loanId")+"");
//		}else{
//			sendErrorMailMsg("ERROR",dataMap.get("userId")+"",dataMap.get("loanId")+"");
//		}
	}
	
	//转换base64
	private String readCustomerDignaturePic(String imgFilePath){
	    InputStream inputStream = null;
	    byte[] data = null;
	    try {
	        inputStream = new FileInputStream(imgFilePath);
	        data = new byte[inputStream.available()];
	        inputStream.read(data);
	        inputStream.close();
	    } catch (IOException e) {
	    	MarvelsLogUtil.getInstance().error("ProcessServiceImpl readCustomerDignaturePic====",e);
	    }
	    //转换base64
	    BASE64Encoder encoder = new BASE64Encoder();
	    return encoder.encode(data);
	}
	
	/**签署合同
	 * @author 娄凯琦
	 * @date 2018年9月28日  
	 * @param loanId
	 * @param picBase64
	 * @param protocolTemplateInfo
	 * @param loanApplyInfo
	 * @return
	 * @throws MarvelsBusinessException 
	 */
	private boolean electronSignAndSeal(String loanId,String picBase64,ProtocolTemplateInfoDTO protocolTemplateInfo,McamLoanApplyInfoDTO loanApplyInfo) throws MarvelsBusinessException{
		MarvelsLogUtil.getInstance().info("ProcessServiceImpl electronSignAndSeal protocolTemplateInfo===="+protocolTemplateInfo);
		//开始初始化双方合同签署
		ResignExternalDTO resignExternalDTO = new ResignExternalDTO();
		resignExternalDTO.setLoanId(loanId);
		resignExternalDTO.setTemplateNo(protocolTemplateInfo.getSignTemplateNo());
		resignExternalDTO.setCustName(loanApplyInfo.getCustName());
		resignExternalDTO.setCustIdNo(loanApplyInfo.getCustCardNo());
		resignExternalDTO.setMobileNum(loanApplyInfo.getMobileNo());
		
		if(-1!=StringUtils.indexOf(ServerProperties.getValue(configPropertiesPath, "resource.properties", "sign.cust.two.num"), protocolTemplateInfo.getTemplateFileName())){
	    	JSONArray signUserArray=new JSONArray();
	    	JSONObject dataObj=new JSONObject();
		    dataObj.put("id_number", loanApplyInfo.getCustCardNo()+"ABC");
		    dataObj.put("signer_name", loanApplyInfo.getCustName()+"TMPN");
		    dataObj.put("user_mobile", loanApplyInfo.getMobileNo()+"TMB");
		    signUserArray.add(dataObj);
		    JSONObject signUserInfo=new JSONObject();
		    signUserInfo.put("userInfo", signUserArray);
		    resignExternalDTO.setUserInfoList(signUserInfo.toString());
	    }
		
		ApiResponse<KimGeXinQianInfo> kimGeResponse = null;
		
		if(-1!=StringUtils.indexOf(protocolTemplateInfo.getTemplateFileName(), ".pdf") ){
			//支持大桔民泰客户承诺书，页面看html，实际用印使用pdf文件
			String fileName = protocolTemplateInfo.getTemplateFileName().substring(0, protocolTemplateInfo.getTemplateFileName().lastIndexOf("."))+".pdf";
		    byte[] by = null;
		    InputStream is=null;
		    try {
		         is = new FileInputStream(protocolTemplateInfo.getTemplateFilePath()+"/"+fileName);
		         ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
	              byte[] bb = new byte[2048];
	              int ch;
	              ch = is.read(bb);
	               while (ch != -1) {
	                   bytestream.write(bb, 0, ch);
	                   ch = is.read(bb);
	               }
	               by = bytestream.toByteArray();
		    } catch (Exception e) {
		    	MarvelsLogUtil.getInstance().error("ProcessServiceImpl electronSignAndSeal loanId===="+loanId,e);
		    }finally {
		    	if(null!=is){
		    		try {
						is.close();
					} catch (IOException e) {
						MarvelsLogUtil.getInstance().error("ProcessServiceImpl electronSignAndSeal loanId===="+loanId,e);
					}
		    	}
			}
			//初始化pdf签章模板		
			kimGeResponse = consumerExternalFacesigApi.contractInitiationByPdfNew(resignExternalDTO);
		}else{
			//初始化html签章模板	
			resignExternalDTO.setHtml(getLoanCompactHtml(loanId, String.valueOf(protocolTemplateInfo.getTemplateNo()),loanApplyInfo,protocolTemplateInfo));
			kimGeResponse = consumerExternalFacesigApi.getContractInitiationV2(resignExternalDTO);
		}
		
		//初始化失败记录日志返回
		if(100000!=kimGeResponse.getCode()){
			MarvelsLogUtil.getInstance().info("ProcessServiceImpl electronSignAndSeal kimGeResponse loanId===="+loanId);
			return false;
		}
		boolean sealflag = true;
		//双方协议合同ID
		KimGeXinQianInfo data = kimGeResponse.getData();
		String contractId = data.getContract_id();
		List<SignInfo> signInfos = data.getSign_info();
		
		//可签字列表中以ENT_开头为公司签章
		int index = 0;
		for (SignInfo signInfo : signInfos) {
			String signName = signInfo.getSign_name();
			ResignExternalDTO resignExternal = new ResignExternalDTO();
			Map<String, String> signature = new HashMap<String, String>();
			resignExternal.setLoanId(loanId);
			resignExternal.setIndex(++index+"");
			resignExternal.setContractId(contractId);
			//个人签字
			if (-1==StringUtils.indexOf(signName, "ENT_")){
				//String signUserId = signInfo.getUser_id();
				resignExternal.setUserId(signInfo.getUser_id());
				resignExternal.setPicBase64(picBase64);
				//调用第三方的签名
				ApiResponse<String> contractSignature = consumerExternalFacesigApi.getContractSignatureV2(resignExternal);
				if(contractSignature.getCode()!=0){
					MarvelsLogUtil.getInstance().info("ProcessServiceImpl electronSignAndSeal contractSignature loanId===="+loanId);
					sealflag = false;
				}
			}else{
				//公司印章
				//String signUserId = signInfo.getUser_id();
				resignExternal.setUserId(signInfo.getUser_id());
				ApiResponse<String> kimResp = consumerExternalFacesigApi.getContractSignatureV2(resignExternal);
				if(kimResp.getCode()!=0){
					MarvelsLogUtil.getInstance().info("ProcessServiceImpl electronSignAndSeal kimResp loanId===="+loanId);
					sealflag = false;
				}
			}
		}
		//下载合同
		sealflag = downLoadSealPdf(contractId,loanId,protocolTemplateInfo,loanApplyInfo);
		return sealflag;
	}
	
	//公司盖章调用	
	private boolean downLoadSealPdf(String contractId,String loanId,ProtocolTemplateInfoDTO protocolTemplateInfo,McamLoanApplyInfoDTO loanApplyInfo){
		try{
			Date applyDate = loanApplyInfo.getApplyTime();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			String[] dateStr = sdf.format(applyDate).split("-");
			StringBuffer folder = new StringBuffer();
			folder.append("/")
			  .append(dateStr[0])
			  .append("/")
			  .append(dateStr[1])
			  .append("/")
			  .append(dateStr[2])
			  .append("/");
			//存储用印最终合同文件ServerProperties.getValue(configPropertiesPath, "resource.properties", "nas.file.path")
			String fileFolder = ServerProperties.getValue(configPropertiesPath, "resource.properties", "nas.file.path")+folder.toString();
			createFile(fileFolder);
			String filePath = "compact_seal_"+loanApplyInfo.getLoanId()+"_"+protocolTemplateInfo.getTemplateNo()+".pdf";
			String atmtType = "SEAL_PDF"+"_"+protocolTemplateInfo.getTemplateNo();
			McamAcLoanApplyImageInfo mcamAcLoanApplyImageInfo = new McamAcLoanApplyImageInfo();
			mcamAcLoanApplyImageInfo.setAtmtType(atmtType);
			mcamAcLoanApplyImageInfo.setUploadUserId("SignSystem");
			mcamAcLoanApplyImageInfo.setUploadTime(new Date());
			mcamAcLoanApplyImageInfo.setFileLocation(fileFolder+filePath);
			mcamAcLoanApplyImageInfo.setFileName(protocolTemplateInfo.getTemplateAbbr());
			mcamAcLoanApplyImageInfo.setFileId(contractId);
			mcamAcLoanApplyImageInfo.setLoanId(loanId);
			attachmentInfoDao.insertAttachmentInfo(mcamAcLoanApplyImageInfo);
			ResignExternalDTO resignExternalDTO = new ResignExternalDTO();
			resignExternalDTO.setContractId(contractId);
			ApiResponse<String> kimResp = consumerExternalFacesigApi.getDownloadDocuments(resignExternalDTO);
			filePath = fileFolder+filePath;
			writeCompactToPdf(kimResp.getMsg(),filePath);
			return true;
		} catch (IOException e) {
			MarvelsLogUtil.getInstance().error("ProcessServiceImpl downLoadSealPdf loanId===="+loanId,e);
			return false;
		}
	}
	
	//将用印合同写入文件并将文件路径存入数据库
	private String writeCompactToPdf(String base64Str,String filePath) throws IOException{
			byte[] bytes = new BASE64Decoder().decodeBuffer(base64Str);
			FileOutputStream fout = new FileOutputStream(new File(filePath));
			fout.write(bytes);
			fout.flush();
			fout.close();
			return filePath;
	}
	
	
	/**
	 * @Title:createFile 
	 * @description:新建文件或文件夹
	 * @author yuanjun
	 * @param filePath：目标文件名（完整路径）
	 * @throws IOException
	 * @return boolean
	 */
	private  boolean createFile(String filePath) throws IOException {
		if (filePath == null || "".equals(filePath.trim())) {
			throw new IOException("filePath is " + null + " or null String");
		}
		if (filePath.indexOf("/") != -1 && filePath.indexOf("\\") != -1) {
			throw new IOException("The filePath " + filePath + " is "
					+ " invalid");
		}
		File file = new File(filePath);
		boolean isDirectory = false;
		// 判断是否文件夹,若是文件夹则创建后返回
		if (filePath.lastIndexOf("/") == filePath.length() - 1
				|| filePath.lastIndexOf("\\") == filePath.length() - 1) {
			isDirectory = true;
		}
		if (isDirectory) {// 是文件夹
			if (file.isDirectory()) {// 若已存在,则无需创建,直接返回
				return true;
			} else {// 若不存在,则创建
				return createMkdirsOrFiles(filePath, 1);
			}
		} else {// 是文件
			if (file.isFile()) {// 若文件存在,则先删除,在创建,再返回
				boolean fd = file.delete();
				if (fd)
					return file.createNewFile();
				else
					return true;// 是否应该返回true,因为目标文件可能是删除不掉的原来的文件
			} else {// 若文件不存在,先创建,再返回
				return createMkdirsOrFiles(filePath, 2);
			}
		}
	}
	
	/**
	 * @Title:createMkdirsOrFiles 
	 * @description:创建文件夹或文件（目标文件或文件夹不存在）
	 * @author yuanjun
	 * @param filePath
	 * @param type：1-文件夹	2-文件
	 * @return boolean
	 * @throws IOException
	 */
	private static boolean createMkdirsOrFiles(String filePath, int type) throws IOException {
		// boolean res = false ;
		File file = new File(filePath);
		if (type == 1) {
			if (file.isDirectory())
				return true;
			file.mkdirs();
			return file.isDirectory();
		} else if (type == 2) {
			
			int index1 = file.getPath().indexOf(File.separator);
			if (index1 != -1) {
				int index2 = file.getPath().indexOf(File.separator, index1 + 1);
				if (index2 != -1) {
					int indexLast = file.getPath().lastIndexOf(File.separator);
					String dir = filePath.substring(0, indexLast + 1);
					File f = new File(dir);
					if (!f.isDirectory()) {
						f.mkdirs();
						boolean res = f.isDirectory();
						if (res) {
							file.createNewFile();
							return file.exists();
						} else {
							return false;
						}
					} else {
						file.createNewFile();
						return file.exists();
					}
				} else {
					file.createNewFile();
					return file.exists();
				}
			}else{
				throw new IOException("The filePath:" + filePath + " separator is " + " invalid");				
			}
		} else
			return false;
	}
	
	
	//核定金额大写
	private String change(BigDecimal amount) {
		if (amount.doubleValue() < 0 || amount.doubleValue() > MAX_VALUE) {
			return "参数非法!";
		}
        BigDecimal bigDecimal = amount.multiply(new BigDecimal(100));
		if (bigDecimal.doubleValue() == 0) {
			return "零元整";
		}
		String strValue = String.valueOf(bigDecimal.toBigInteger());
		// i用来控制数
		int i = 0;
		// j用来控制单位
		int j = UNIT.length() - strValue.length();
		String rs = "";
		boolean isZero = false;
		for (; i < strValue.length(); i++, j++) {
			char ch = strValue.charAt(i);
			if (ch == '0') {
				isZero = true;
				if (UNIT.charAt(j) == '亿' || UNIT.charAt(j) == '万' || UNIT.charAt(j) == '元') {
					rs = rs + UNIT.charAt(j);
					isZero = false;
				}
			} else {
				if (isZero) {
					rs = rs + "零";
					isZero = false;
				}
				rs = rs + DIGIT.charAt(ch - '0') + UNIT.charAt(j);
			}
		}
		if (!rs.endsWith("分")) {
			rs = rs + "整";
		}
		rs = rs.replaceAll("亿万", "亿");
		return rs;
	}
	
	//初始化html签章模板
	private String getLoanCompactHtml(String loanId,String templateNo,McamLoanApplyInfoDTO loanApplyInfo,ProtocolTemplateInfoDTO protocolTemplateInfo) throws MarvelsBusinessException {
		//定义资金源
		String fundSource = null;
		Long productId=Long.valueOf("0");
		Integer terms = Integer.getInteger("0");
		Map<String,Object> resultMap = new HashMap<String,Object>();
		//申请人姓名
		resultMap.put("borrower", null==loanApplyInfo.getCustName()?" ":loanApplyInfo.getCustName());
		//申请人身份证编号
		resultMap.put("borrowerCardId", null==loanApplyInfo.getCustCardNo()?" ":loanApplyInfo.getCustCardNo());
		//申请人地址
		resultMap.put("borrowerAddress", null==loanApplyInfo.getCustCardAddress()?" ":loanApplyInfo.getCustCardAddress());
		//申请人电话
		resultMap.put("borrowerCellPhnone", null==loanApplyInfo.getMobileNo()?" ":loanApplyInfo.getMobileNo());
		//还款卡号
		resultMap.put("borrowerBankCardNo", null==loanApplyInfo.getPaymentAcctNo()?" ":loanApplyInfo.getPaymentAcctNo());
		//借款人邮编
		resultMap.put("borrowerPostCode", " ");
		//借款还款账户开户名
		resultMap.put("borrowerBankUserName", null==loanApplyInfo.getPaymentAcctName()?" ":loanApplyInfo.getPaymentAcctName());
		//借款人还款账户开户行名称
		resultMap.put("borrowerBankName", null==loanApplyInfo.getPaymentBankName()?" ":loanApplyInfo.getPaymentBankName());
		//借款用途
		resultMap.put("loanUse", null==loanApplyInfo.getPurpose()?" ":loanApplyInfo.getPurpose());	
		//核定金额大写
		resultMap.put("loanCapitalUpper", null==loanApplyInfo.getPrincipalAmtAct()?" ":change(loanApplyInfo.getPrincipalAmtAct()));
		//核定金额小写
		resultMap.put("loanCapitalLower", null==loanApplyInfo.getPrincipalAmtAct()?" ":loanApplyInfo.getPrincipalAmtAct());	
		//电子邮箱
		resultMap.put("borrowerEmail", null==loanApplyInfo.getEmail()?" ":loanApplyInfo.getEmail());
		//期数
		terms = loanApplyInfo.getApplyTerms();
		//产品ID
		productId=Long.parseLong(loanApplyInfo.getProductCode());
		
		fundSource = loanApplyInfo.getFundCode();
		
		//贷款期数
		resultMap.put("loanPeriod", terms);
		Calendar calendar = Calendar.getInstance();
		Date startDate = new Date();
		calendar.add(Calendar.MONTH, terms);
		Date endDate = calendar.getTime();
		int loanDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000);
		resultMap.put("loanDays", loanDays);
		LaAttachmentDTO laAttachmentDTO = new LaAttachmentDTO();
		laAttachmentDTO.setLoanId(loanId);
		laAttachmentDTO.setAtmtType("Q_MQ");//Q_MQ表示签名附件
		List<LaAttachmentDTO> attList = attachmentInfoService.getAttachmentByLoanIdAndType(laAttachmentDTO);//查询附件
		Date signDate = null;
		if(null!=attList && attList.size()>0){
			signDate = attList.get(0).getUploadTime();
		}else{
			signDate= Calendar.getInstance().getTime();
		}
		
		Date borrowIssueDate = DateUtils.add(signDate, Calendar.DAY_OF_MONTH, 2);
		String[] borrowIssueDateStr = DateUtils.getDateYYYY_MM_DD(borrowIssueDate).split("-");
		resultMap.put("borrowIssueYear", borrowIssueDateStr[0]);
		resultMap.put("borrowIssueMonth", borrowIssueDateStr[1]);
		resultMap.put("borrowIssueDay", borrowIssueDateStr[2]);
		resultMap.put("borrowIssueDate", DateUtils.getDateYYYY_MM_DD(borrowIssueDate));
		//贷款到期Y-M-D日  预计发放日月份+期数
		Date borrowExpireDate = DateUtils.add(borrowIssueDate, Calendar.MONTH, terms.intValue());
		String[] borrowExpireDateStr = DateUtils.getDateYYYY_MM_DD(borrowExpireDate).split("-");
		resultMap.put("borrowExpireYear", borrowExpireDateStr[0]);
		resultMap.put("borrowExpireMonth", borrowExpireDateStr[1]);
		resultMap.put("borrowExpireDay", borrowExpireDateStr[2]);
		resultMap.put("borrowExpireDate", DateUtils.getDateYYYY_MM_DD(borrowExpireDate));
		
		String[] ymd = DateUtils.getDateYYYY_MM_DD(signDate).split("-");
		resultMap.put("contractYear", ymd[0]);
		resultMap.put("contractMonth", ymd[1]);
		resultMap.put("contractDay", ymd[2]);		
		//先查询是否已经有合同编号AcLoanApplyInfo
		String compactCode = loanApplyInfo.getFjContractNo();
		if(StringUtils.isEmpty(compactCode)){
			compactCode = "CT-XD-01-"+ymd[0]+ymd[1];
		}
		resultMap.put("compactCode", compactCode);
		
		String externalContract = loanApplyInfo.getContractNo();
		if(externalContract!= null && !"".equals(externalContract.trim())){
			resultMap.put("externalContract", externalContract);
		}else{
			resultMap.put("externalContract", "");
		}
		double manageFee = loanApplyInfo.getProductManagementRate().doubleValue();
		
		String paramName = "FUND_SOURCE_" + fundSource + "_TERMS_" +terms;
		
		McsmSystemParam mcsmSystemParam = new McsmSystemParam();
		mcsmSystemParam.setParamName(paramName);
		McsmSystemParam sysResult = consumerSystemApi.paramList(mcsmSystemParam).get(0);
		String value = sysResult.getParamValue();
		if (value == null) {
			value = "0";
		}
		BigDecimal tmFee = new BigDecimal(value);
		BigDecimal mFee = new BigDecimal(manageFee);
		manageFee = mFee.add(tmFee).doubleValue();
		String managementFee = new BigDecimal(manageFee+"").multiply(new BigDecimal("100")).doubleValue()+"";
		resultMap.put("managementFee", managementFee);
		//咨询费
		String counselFee = (loanApplyInfo.getProductConsultingRate().doubleValue()*100)+"";
		resultMap.put("counselFee", counselFee);
		
		String yearRate = (loanApplyInfo.getRate().doubleValue()*100)+"%";
		
		//xie
		String paramRate = "RATE_FUND_" + fundSource + "_" +productId;
		mcsmSystemParam.setParamName(paramRate);
		sysResult = consumerSystemApi.paramList(mcsmSystemParam).get(0);
		String rateVal = sysResult.getParamValue();
		if(rateVal!=null && !rateVal.equals("")){
			resultMap.put("yearRate", rateVal);
		}
		
		LoanAfterInfoDTO loanAfterInfoDTO = new LoanAfterInfoDTO();
		loanAfterInfoDTO.setAmount((BigDecimal)resultMap.get("loanCapitalLower"));// 实际借款总额
		loanAfterInfoDTO.setDate(new Date());// 放款时间
		loanAfterInfoDTO.setProductCode(productId+"");// 产品小类code
		loanAfterInfoDTO.setTenor(terms);// 期数
		loanAfterInfoDTO.setFundSource(loanApplyInfo.getFundCode());// 资金源code
		loanAfterInfoDTO.setLoanId(loanApplyInfo.getLoanId());// 贷款id
		LoanAfterInfoDTO resultInfo = consumerFinancialApi.loanTrial(loanAfterInfoDTO);//贷款试算
		resultMap.put("consultingFee", resultInfo.getConsultingFee());
		resultMap.put("aviAmount", resultInfo.getAviAmount());
		resultMap.put("serviceFee", resultInfo.getManagementFee());
		resultMap.put("monthlyAmount", resultInfo.getMonthlyAmount());
		
		Configuration configuration = new Configuration();
		StringWriter strWrite = new StringWriter();
        try {
			configuration.setDirectoryForTemplateLoading(new File(protocolTemplateInfo.getTemplateFilePath()));
		
        configuration.setDefaultEncoding("UTF-8");
        // 获取或创建一个模版。  
        Template template = configuration.getTemplate(protocolTemplateInfo.getTemplateFileName());
        // 获取html静态页面文件
        template.process(resultMap, strWrite);
        strWrite.close();
        } catch (Exception e) {
        	MarvelsLogUtil.getInstance().error("ProcessServiceImpl getLoanCompactHtml",e);
		}
        return strWrite.getBuffer().toString();
	}
	@Override
	public void timingLoanCompactSign(){
		String batchName=UUID.randomUUID().toString().replace("-", "");
		int count=mcamResignStateMsgDao.updateBatchName(batchName);
		if(count<1){
			MarvelsLogUtil.getInstance().info(">>>>>没有需要签约的进件");
			return;
		}
		List<McamResignStateMsgDTO> list=mcamResignStateMsgDao.selectByBatchName(batchName);
		if(list==null || list.size()<1){
			MarvelsLogUtil.getInstance().info(">>>>>没有需要签约的进件");
			return;
		}
		for(McamResignStateMsgDTO msgDTO:list){
			String loanId=msgDTO.getLoanId();
			boolean result=false;
			try {
				result=loanCompactSign(loanId);
			} catch (Exception e) {
				MarvelsLogUtil.getInstance().error(">>>>>loanId:"+loanId+",签约失败:",e);
			}
			McamResignStateMsgDTO dto=new McamResignStateMsgDTO();
			if(result){//成功
				dto.setState("2");//合同状态 1:未签约2:已签约  3签约失败
			}else{
				dto.setState("3");//合同状态 1:未签约2:已签约  3签约失败
			}
			dto.setId(msgDTO.getId());
			dto.setUpdateBy("system");
			dto.setUpdateTime(new Date());
			mcamResignStateMsgDao.updateByPrimaryKeySelective(msgDTO);
		}
		MarvelsLogUtil.getInstance().info(">>>>>签约完毕");
	}
	
	@Override
	public void handleZSJProcessByLoanId(String loanId) throws MarvelsBusinessException {
		boolean result = false;
		try {
			List<String> queryNodes = new ArrayList<String>();
			queryNodes.add(CaseNodeConstant.WOCHECKING.getCode());
			queryNodes.add(CaseNodeConstant.WOAPPROVAL.getCode());
			queryNodes.add(CaseNodeConstant.WOSAMPLING.getCode()); 
			HandleProcessDTO handleProcessDTO = new HandleProcessDTO();
			handleProcessDTO.setQueryNodes(queryNodes);
			handleProcessDTO.setLoanId(loanId);
			
			//1\拿用户角色
			UserDTO user = CacheUtils.getCacheUser();
			if(user == null){
				throw new MarvelsBusinessException("无法获取登录信息,token:" + ThreadContextUtil.get("l-token"));
			}
			SysUserDTO dto = this.sysUserService.querySysUser(user.getUserId());
			if(dto==null){
				throw new MarvelsBusinessException("无法获取到操作人信息,操作人ID:" + user.getUserId());
			}
			List<SysUserRoleDTO> roles = dto.getRoles();
			List<String> roleCodes = new ArrayList<String>();
			int count = roles==null?0:roles.size();
			for(int i=0;i<count;i++){
				roleCodes.add(roles.get(i).getRoleCode());
			}
			handleProcessDTO.setRoleCodes(roleCodes);
			LoanApplyCaseDTO loanApplyCase = loanApplyCaseService.findLoanApplyCasesByLoanId(handleProcessDTO);
		    //3\获取这些节点下那些贷款单 
		    //4\拿去1单处理  
		    //5\修改mcam_loan_apply_case update assignee is null
			if(loanApplyCase == null){
				throw new MarvelsBusinessException("该单已经无效");
			}
			
			loanApplyCase.setCurAssignee(null);
			loanApplyCase.setAssignee(user.getUserCode());
			loanApplyCase.setAssigneeName(user.getUserName());
			Integer caseVersion = loanApplyCase.getCaseVersion();
			loanApplyCase.setCaseVersion(caseVersion==null?1:caseVersion);
			LoanApplyCaseDTO loanApplyCaseDto = this.loanApplyCaseService.pickupLoanApplyCases(loanApplyCase);
			if(loanApplyCaseDto != null){
				//写入log
				loanApplyCaseLogService.commCompleteCase(loanApplyCaseDto,null);
				result = true;
			}
			//征信，审批，审计 状态流转
			modifyStatus(loanId);
			if(!result){
				throw new MarvelsBusinessException("主动取件未成功" + loanId);
			}
		} catch (Exception e) {
			throw new MarvelsBusinessException("主动取件异常" + loanId);
		}
	}
	
}
